use rand::Rng;
use std::cmp::Ordering;
use std::io;
use std::{thread, time};

fn main() {
    let secret_number = rand::thread_rng().gen_range(1..=100);
    println!("我是一个变量:{}, 随机生成。", secret_number);

    const THREE_HOURS_IN_SECONDS: u32 = 60 * 60 * 3;
    println!(
        "我是一个常量:{}, 值的类型必须指定。",
        THREE_HOURS_IN_SECONDS
    );

    // 隐藏函数
    yicang(THREE_HOURS_IN_SECONDS, 'h');

    // 浮点型
    let x = 2.0; // f64
    let y: f32 = 3.0; // f32

    // 数值运算函数
    comp();

    // 字符串
    // 我们用单引号声明 char 字面量，而与之相反的是，使用双引号声明字符串字面量。
    let zzz: char = 'ℤ'; // with explicit type annotation
    let heart_eyed_cat = '😻';
    println!("heart_eyed_cat:{}, zzz：{}。", heart_eyed_cat, zzz);

    // 元组
    let tup: (i32, f64, u8) = (500, 6.4, 1);
    // 解构
    let (x, y, z) = tup;
    println!("tup：{}, x:{}。", tup.0, x);

    // 数组越界函数
    outOfArrayIndex(true);

    func();

    let mut getVal = getFuncReturnValue();
    println!("getFuncReturnValue is: {getVal}");

    flowIf();

    flowLoop(5);

    // 从循环返回值
    flowLoopGetValue();

    // 循环标签：在多个循环之间消除歧义
    flowLoopMore();

    whileTest();
    whileList();
    forList();
}

/*
隐藏变量

第二个变量“遮蔽”了第一个变量，此时任何使用该变量名的行为中都会视为是在使用第二个变量，直到第二个变量自己也被隐藏或第二个变量的作用域结束。
可以用相同变量名称来隐藏一个变量，以及重复使用 let 关键字来多次隐藏
*/
fn yicang(x: u32, unit_label: char) {
    println!(" ");
    println!("隐藏变量:{}/{}", x, unit_label);

    // x=5
    let x = 5;

    // x=6
    let x = x + 1;

    {
        // x = 6 * 2
        let x = x * 2;
        println!("The value of x in the inner scope is: {x}");
    }

    println!("The value of x is: {x}");
}

/*
数值运算
*/
fn comp() {
    println!(" ");
    println!("数值运算");

    // addition
    let sum = 5 + 10;
    assert_eq!(sum, 15);

    // subtraction
    let difference = 95.5 - 4.3;
    assert_eq!(difference, 91.2);

    // multiplication
    let product = 4 * 30;
    assert_eq!(product, 120);

    // division
    let quotient = 56.7 / 32.2;
    assert_eq!(quotient, 1.7608695652173911);
    let floored = 2 / 3; // Results in 0
    assert_eq!(floored, 0);

    // remainder
    let remainder = 43 % 5;
    assert_eq!(remainder, 3);

    println!(
        "sum: {}， difference：{}， product：{}，quotient:{}, floored:{}, remainder:{}",
        sum, difference, product, quotient, floored, remainder
    );
}

/*
数组越界
*/
fn outOfArrayIndex(skip: bool) {
    println!(" ");
    println!("数组越界, skip:{}", skip);

    if skip {
        return;
    }

    // 数组
    let a = [1, 2, 3, 4, 5];
    println!("数组:{a:?}");

    /*
     如果输入的值大于等于5， 则会报错：
     thread 'main' panicked at 'index out of bounds: the len is 5 but the index is 5'
     */
    let mut index: String = String::new();
    loop {
        println!("Please enter an array index.");

        io::stdin()
            .read_line(&mut index)
            .expect("Failed to read line");

        // 移除空格和换行符
        let _index: &str = index.trim().trim_end_matches("\n");
        if(_index.is_empty()){
            continue
        }else if(_index.eq_ignore_ascii_case("exit")){
            // 退出
            return;
        }else{
            index = _index.to_string();
            break;
        }
    }
    let index: usize = index
        .trim()
        .parse()
        .expect("Index entered was not a number");

    let element = a[index];
    println!("The value of the element at index [{index}] is: {element}");
}

fn func(){
    let y = {
        let x = 3;
        x + 1     // 注意： 在结尾没有分号。 表达式的结尾没有分号。如果在表达式的结尾加上分号，它就变成了语句，而语句不会返回值。
    };  // 该代码块的执行结果绑定到 y 上。

    assert_eq!(y, 4);
    println!("The value of y is: {y}");
}

// 带返回值的函数
fn getFuncReturnValue() -> i32 {
    // 没有分号，因为这是一个表达式，我们想要返回它的值。
    5
}

// 控制流 if
fn flowIf() {
    let number = 3;

    if number < 5 {
        println!("flowIf condition was true");
    } else {
        println!("flowIf condition was false");
    }
}

// loop
fn flowLoop(maxCount: i32) {
    let mut count = 0;

    loop {
        if count > maxCount{
            break;
        }

        let ten_millis = time::Duration::from_millis(100);
        let now = time::Instant::now();

        thread::sleep(ten_millis);
        assert!(now.elapsed() >= ten_millis);

        println!("again {} times {} ms!", count, ten_millis.as_millis());

        count += 1;
    }
}

// 从循环返回值
fn flowLoopGetValue() {
    // 在循环之前，我们声明了一个名为 counter 的变量并初始化为 0。
    let mut counter = 0;

    // 声明了一个名为 result 来存放循环的返回值。
    let result = loop {
        // 在循环的每一次迭代中，我们将 counter 变量加 1，接着检查计数是否等于 10。当相等时，使用 break 关键字返回值 counter * 2 + 5。
        counter += 1;

        let ten_millis = time::Duration::from_millis(10);
        thread::sleep(ten_millis);

        if counter == 10 {
            break counter * 2 + 5;
        }
    }; // 循环之后，我们通过分号结束赋值给 result 的语句。

    assert_eq!(result, 25);
    println!("flowLoopGetValue result is {result}");
}

// 循环标签：在多个循环之间消除歧义
fn flowLoopMore() {
    let mut count = 0;

    // 外层循环有一个标签 counting_up，它将count 从 0 数到 2。
    'counting_up: loop {
        println!("count = {count}");
        let mut remaining = 10;

        // 没有标签的内部循环从 10 向下数到 9。
        loop {
            println!("remaining = {remaining}");
            if remaining == 9 {
                // 退出内层循环
                break;
            }
            if count == 2 {
                // 退出外层循环
                break 'counting_up;
            }
            remaining -= 1;
        }

        count += 1;
    }
    println!("End count = {count}");
}

fn whileTest() {
    let mut number = 3;

    while number != 0 {
        println!("whileTest {number}!");

        number -= 1;
    }

    /*
    输出
    whileTest 3!
    whileTest 2!
    whileTest 1!
    */
}

// 使用 while 循环遍历集合中的元素
fn whileList() {
    let a = [10, 20, 30, 40, 50];
    let mut index = 0;

    while index < 5 {
        println!("whileList the value is: {}", a[index]);

        index += 1;
    }
}

fn forList() {
    let a = [10, 20, 30, 40, 50];

    for element in a {
        println!("forList the value is: {element}");
    }

    // 输出 3，2，1
    // rev() 方法位反转range
    for number in (1..4).rev() {
        println!("forList {number}!");
    }
    println!("LIFTOFF!!!");
}